﻿using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Organizations;
using Abp.Runtime.Caching;
using AbpProjectTemplate.Domain.Roles;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Linq;

namespace AbpProjectTemplate.Domain.Users
{
    public class UserManager : AbpUserManager<Role, User>
    {
        public UserManager(
            RoleManager roleManager,
            UserStore store,
            IOptions<IdentityOptions> optionsAccessor,
            IPasswordHasher<User> passwordHasher,
            IEnumerable<IUserValidator<User>> userValidators,
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            ILookupNormalizer keyNormalizer,
            IdentityErrorDescriber errors,
            IServiceProvider services,
            ILogger<UserManager<User>> logger,
            IPermissionManager permissionManager,
            IUnitOfWorkManager unitOfWorkManager,
            ICacheManager cacheManager,
            IRepository<OrganizationUnit, long> organizationUnitRepository,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IOrganizationUnitSettings organizationUnitSettings,
            ISettingManager settingManager,
            IUserCache userCache, 
            IRepository<UserLogin, long> userLoginRepository)
            : base(
                roleManager,
                store,
                optionsAccessor,
                passwordHasher,
                userValidators,
                passwordValidators,
                keyNormalizer,
                errors,
                services,
                logger,
                permissionManager,
                unitOfWorkManager,
                cacheManager,
                organizationUnitRepository,
                userOrganizationUnitRepository,
                organizationUnitSettings,
                settingManager,
                userLoginRepository)
        {
            this.UserCache = userCache;
            this.PasswordValidators.Clear();
        }

        public IUserCache UserCache { get; }

        private IUserRoleStore<User> GetUserRoleStore()
        {
            var cast = this.Store as IUserRoleStore<User>;
            if (cast == null)
            {
                throw new NotSupportedException("role store is not supported");
            }
            return cast;
        }
        /// <summary>
        /// 【已缓存】根据登录身份获取用户
        /// </summary>
        public override async Task<User> GetUserAsync(ClaimsPrincipal principal)
        {
            var userId = this.GetUserId(principal);
            return await this.UserCache.GetAsync(Convert.ToInt64(userId));
        }

        public override async Task<IdentityResult> AddToRolesAsync(User user, IEnumerable<string> roles)
        {
            this.ThrowIfDisposed();
            var userRoleStore = this.GetUserRoleStore();
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (roles == null)
            {
                throw new ArgumentNullException(nameof(roles));
            }
            var currRoles = await this.GetRolesAsync(user);
            var delRoles = currRoles.Where(t => !roles.Contains(t));
            await this.RemoveFromRolesAsync(user, delRoles);
            foreach (var role in roles.Distinct())
            {
                var normalizedRole = this.NormalizeName(role);
                if (await userRoleStore.IsInRoleAsync(user, normalizedRole, this.CancellationToken))
                {
                    continue;
                }
                await userRoleStore.AddToRoleAsync(user, normalizedRole, this.CancellationToken);
            }
            return await this.UpdateUserAsync(user);
        }
    }
}

